package com.yzy.domain.strategy;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import com.google.common.base.Preconditions;
import com.yzy.domain.strategy.model.entity.RaffleAwardEntity;
import com.yzy.domain.strategy.model.entity.RaffleFactorEntity;

import com.yzy.domain.strategy.repository.IStrategyRepository;
import com.yzy.domain.strategy.service.armory.IStrategyDispatch;
import com.yzy.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import com.yzy.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;


import lombok.extern.slf4j.Slf4j;

/**
 * @author yangzhenyu05 <yangzhenyu05@kuaishou.com>
 * Created on 2024-01-14
 * @description 抽奖模版类
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy,IRaffleStock {
    // 策略仓储服务 -> domain层像一个大厨，仓储层提供米面粮油
    protected IStrategyRepository repository;
    // 策略调度服务 -> 只负责抽奖处理，通过新增接口的方式，隔离职责，不需要使用方关心或者调用抽奖的初始化
    protected IStrategyDispatch strategyDispatch;
    // 抽奖的责任链 -> 从抽奖的规则中，解耦出前置规则为责任链处理
    protected final DefaultChainFactory defaultChainFactory;
    // 抽奖的决策树 -> 负责抽奖中到抽奖后的规则过滤，如抽奖到A奖品ID，之后要做次数的判断和库存的扣减等。
    protected final DefaultTreeFactory defaultTreeFactory;


    public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch,
            DefaultChainFactory defaultChainFactory, DefaultTreeFactory defaultTreeFactory) {
        this.repository = repository;
        this.strategyDispatch = strategyDispatch;
        this.defaultChainFactory = defaultChainFactory;
        this.defaultTreeFactory = defaultTreeFactory;
    }

    @Override
    public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {
        // 1. 参数校验
        checkArgument(raffleFactorEntity);

        // 2. 获取抽奖责任链
        DefaultChainFactory.StrategyAwardVO chainStrategyAwardVO =
                raffleLogicChain(raffleFactorEntity.getUserId(), raffleFactorEntity.getStrategyId());
        log.info("抽奖策略计算-责任链 {} {} {} {}", raffleFactorEntity.getUserId(), raffleFactorEntity.getStrategyId(),
                chainStrategyAwardVO.getAwardId(), chainStrategyAwardVO.getLogicModel());
        if (!DefaultChainFactory.LogicModel.RULE_DEFAULT.getCode().equals(chainStrategyAwardVO.getLogicModel())) {
            return RaffleAwardEntity.builder()
                    .awardId(chainStrategyAwardVO.getAwardId())
                    .build();
        }

        // 3. 规则树抽奖过滤【奖品ID，会根据抽奖次数判断、库存判断、兜底兜里返回最终可获得奖品信息】
        DefaultTreeFactory.StrategyAwardVO treeStrategyAwardVO =
                raffleLogicTree(raffleFactorEntity.getUserId(), raffleFactorEntity.getStrategyId(),
                        chainStrategyAwardVO.getAwardId());
        log.info("抽奖策略计算-规则树 {} {} {} {}", raffleFactorEntity.getUserId(), raffleFactorEntity.getStrategyId(),
                treeStrategyAwardVO.getAwardId(), treeStrategyAwardVO.getAwardRuleValue());

        return RaffleAwardEntity.builder()
                .awardConfig(treeStrategyAwardVO.getAwardRuleValue())
                .awardId(treeStrategyAwardVO.getAwardId())
                .build();
    }

    /**
     * 抽奖计算，责任链抽象方法
     *
     * @param userId 用户ID
     * @param strategyId 策略ID
     * @return 奖品ID
     */
    public abstract DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId);

    /**
     * 抽奖结果过滤，决策树抽象方法
     *
     * @param userId 用户ID
     * @param strategyId 策略ID
     * @param awardId 奖品ID
     * @return 过滤结果【奖品ID，会根据抽奖次数判断、库存判断、兜底兜里返回最终可获得奖品信息】
     */
    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId);


    /**
     * 参数校验
     *
     * @param raffleFactorEntity 基础参数
     */
    private void checkArgument(RaffleFactorEntity raffleFactorEntity) {
        Preconditions.checkArgument(ObjectUtils.isEmpty(raffleFactorEntity.getStrategyId()),
                "非法参数！strategyId为空！");
        Preconditions.checkArgument(StringUtils.isBlank(raffleFactorEntity.getUserId()), "非法参数！userId为空");
    }

}
